package 每日一题;

import java.util.*;

/**
 * 207. 课程表
 * 提示
 * 中等
 * 1.7K
 * 相关企业
 * 你这个学期必须选修 numCourses 门课程，记为 0 到 numCourses - 1 。
 *
 * 在选修某些课程之前需要一些先修课程。 先修课程按数组 prerequisites 给出，其中 prerequisites[i] = [ai, bi] ，表示如果要学习课程 ai 则 必须 先学习课程  bi 。
 *
 * 例如，先修课程对 [0, 1] 表示：想要学习课程 0 ，你需要先完成课程 1 。
 * 请你判断是否可能完成所有课程的学习？如果可以，返回 true ；否则，返回 false 。
 *
 *
 *
 * 示例 1：
 *
 * 输入：numCourses = 2, prerequisites = [[1,0]]
 * 输出：true
 * 解释：总共有 2 门课程。学习课程 1 之前，你需要完成课程 0 。这是可能的。
 * 示例 2：
 *
 * 输入：numCourses = 2, prerequisites = [[1,0],[0,1]]
 * 输出：false
 * 解释：总共有 2 门课程。学习课程 1 之前，你需要先完成​课程 0 ；并且学习课程 0 之前，你还应先完成课程 1 。这是不可能的。
 *
 *
 * 提示：
 *
 * 1 <= numCourses <= 2000
 * 0 <= prerequisites.length <= 5000
 * prerequisites[i].length == 2
 * 0 <= ai, bi < numCourses
 * prerequisites[i] 中的所有课程对 互不相同
 */
public class T207_课程表 {

    //如果没有先决条件 此课程入度为0  有几个先修课程入度为几，将入度为0的课程先修完 后修课程入度减少到0就可以继续选，直到没有入度为0的课程
    //类似BFS的做法
    public boolean canFinish(int numCourses, int[][] prerequisites) {

        //记录每个课程的入度情况
        int[] numberOfPreconditions = new int[numCourses];
        //记录该课程的直接后续课程
        HashMap<Integer, List<Integer>> mapCourseNext = new HashMap<>();
        //修完的课程数
        int count = 0;
        for (int i = 0; i < prerequisites.length; i++) {
            int[] prerequisite = prerequisites[i];
            //每出现一个前置课程 该课程入度+1
            numberOfPreconditions[prerequisite[0]]++;
            //将该课程加入到前置课程的next数组中
            List<Integer> next = mapCourseNext.getOrDefault(prerequisite[1], new ArrayList<Integer>());
            next.add(prerequisite[0]);
            mapCourseNext.put(prerequisite[1], next);
        }

        //存放入度为0 的课程 模拟修完的过程
        Queue<Integer> queue = new ArrayDeque<>();
        //将初始入度为0的课程放入队列
        for (int i = 0; i < numberOfPreconditions.length; i++) {

            if (numberOfPreconditions[i] == 0) {
                queue.add(i);
                count++;
            }
        }

        //模拟
        while (!queue.isEmpty()) {

            //取出一个课程 完成它 将他的直接后续课程入度减一
            Integer course = queue.poll();

            List<Integer> list = mapCourseNext.getOrDefault(course, new ArrayList<>());

            for (Integer item : list) {
                numberOfPreconditions[item]--;
                //如果直接后续课程的入度变成0 将其入队列
                if (numberOfPreconditions[item] == 0) {
                    queue.add(item);
                    count++;
                }
            }

        }

        return count == numCourses;
    }

    public static void main(String[] args) {
        T207_课程表 test = new T207_课程表();
        test.canFinish(2, new int[][]{{1, 0}});
    }

}
